#include <iostream>
#include <cstring>

#define NAMESIZE 32

using namespace std;

class Student {
    private:
        char *m_name;
        int m_age;
        int m_score;

        static int m_cnt; // 静态成员变量，不属于某个对象，而属于类

    public:
        Student(); // 构造方法，类实例化时默认调用
        Student(const char *name, int age, int score); // 构造方法重载
        Student(const Student &p); // 拷贝构造方法
        ~Student(); // 析构方法，类对象被释放时调用

        static int getCnt(); // 静态方法，没有this指针，只能访问静态成员变量

        void show();
        void setName(const char *name);
        void setAge(int age);
        void setScore(int score);

        int getAge() const; // 常函数

        friend void showInfo(const Student &s); // 友元函数，可以访问对象私有变量，不是成员函数，只是在此声明
        // friend class A; // 友元类同理
};

int Student::m_cnt = 0; // 静态成员变量初始化

Student::Student()
{
    m_cnt++;
    m_name = new char[NAMESIZE];
}

Student::Student(const char *name, int age, int score): m_age(age), m_score(score)
{
    m_cnt++;
    m_name = new char[NAMESIZE];
    strncpy(m_name, name, NAMESIZE);
}

Student::Student(const Student &p): m_age(p.m_age), m_score(p.m_score)
{
    m_cnt++;
    m_name = new char[NAMESIZE];
    // C++的访问控制规则允许类的成员函数访问同类任何对象（包括参数对象）的私有成员。
    strncpy(m_name, p.m_name, NAMESIZE);
}

Student::~Student()
{
    m_cnt--;
    delete[] m_name;
}

int Student::getCnt()
{
    // cout << this->m_name << endl; // 不能访问，报错
    // cout << m_name << endl; // 不能访问，报错
    return m_cnt;
}

void Student::show() 
{
    cout << m_name << ", " << m_age << ", " << m_score << endl;
}

void Student::setName(const char *name)
{
    strncpy(m_name, name, NAMESIZE);
}

void Student::setAge(int age)
{
    this->m_age = age; // this指针，指向调用该方法的哪个对象
}

void Student::setScore(int score)
{
    m_score = score;
}

int Student::getAge() const
{
    return m_age;
}

void showInfo(const Student &s) // 注意此处不是Student::showInfo
{
    cout << "name = " << s.m_name << endl; // 直接访问私有成员
}

int main(void)
{
    Student stu1("小白", 13, 23);

    stu1.show();
    cout << "cnt = " << Student::getCnt() << endl; // 无需实例化，直接通过类名调用

    cout << "age = " << stu1.getAge() << endl;

    showInfo(stu1);
    // stu1.showInfo(); // 不是成员函数，不能通过对象访问

    return 0;
}

